/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.databaseobject.rtmanager;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.transaction.JpaTransaction;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.database.Database;
import io.iec.edp.caf.database.DatabaseManager;
import io.iec.edp.caf.databaseobject.DboDeployManager;
import io.iec.edp.caf.databaseobject.api.configuration.FileUtils;
import io.iec.edp.caf.databaseobject.api.entity.*;
import io.iec.edp.caf.databaseobject.api.service.IDatabaseObjectRtService;
import io.iec.edp.caf.databaseobject.common.DatabaseObjectCheckUtil;
import io.iec.edp.caf.databaseobject.common.DatabaseObjectCommonUtil;
import io.iec.edp.caf.databaseobject.common.helper.TableNameHelper;
import io.iec.edp.caf.databaseobject.common.cache.DatabaseObjectCacheManager;
import io.iec.edp.caf.databaseobject.manager.DatabaseObjectServiceImpl;
import io.iec.edp.caf.databaseobject.rtmanager.repository.GspDatabaseColumnMappingRepository;
import io.iec.edp.caf.databaseobject.rtmanager.repository.GspDatabaseObjectMappingRepository;
import io.iec.edp.caf.databaseobject.rtmanager.repository.GspDatabaseObjectRepository;
import io.iec.edp.caf.databaseobject.spi.ITableNameRuleManager;
import io.iec.edp.caf.dimension.api.entity.DimensionEntity;
import io.iec.edp.caf.i18n.api.LanguageService;
import io.iec.edp.caf.rpc.api.service.RpcClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.collections.ManagedConcurrentWeakHashMap;
import org.springframework.core.env.Environment;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author liu_wei
 */
@Slf4j
public class DatabaseObjectRtService implements IDatabaseObjectRtService {

    private GspDatabaseObjectRepository repository;
    private GspDatabaseObjectMappingRepository mappingRepository;
    private GspDatabaseColumnMappingRepository columnMappingRepository;


    private static JpaTransaction jpaTransaction;

    private static JpaTransaction getJpaTransaction() {
        if (jpaTransaction == null) {
            jpaTransaction = JpaTransaction.getTransaction();
        }
        return jpaTransaction;
    }

    private RpcClient client = SpringBeanUtils.getBean(RpcClient.class);

    public DatabaseObjectRtService(GspDatabaseObjectRepository repository,GspDatabaseObjectMappingRepository mappingRepository,GspDatabaseColumnMappingRepository columnMappingRepository) {
        this.repository = repository;
        this.mappingRepository = mappingRepository;
        this.columnMappingRepository = columnMappingRepository;
    }


    @Override
    public List<AbstractDatabaseObject> getDatabaseObjectList() {
        List<AbstractDatabaseObject> databaseObjectList = new ArrayList<>();
        try {
            List<GspDatabaseObject> gspDatabaseObjects = repository.findAll();
            for (GspDatabaseObject gspDatabaseObject : gspDatabaseObjects) {
                databaseObjectList.add(getDatabaseObjectInfoFromGspDbo(gspDatabaseObject));
            }
        } catch (Exception e) {
            throw new RuntimeException("获取数据库对象列表报错", e);
        }
        return databaseObjectList;
    }

    @Override
    public List<GspDatabaseObject> getGspDatabaseObjectList() {
        try {
            List<GspDatabaseObject> gspDatabaseObjects = repository.findGspDatabaseObjectVoList();
            return gspDatabaseObjects;
        } catch (Exception e) {
            throw new RuntimeException("获取GSP数据库对象列表报错", e);
        }
    }

//  @Override
//    public List<AbstractDatabaseObject> getDatabaseObjectList(String su) {
//        Type<List> type = new Type<>(List.class, AbstractDatabaseObject.class);
//        LinkedHashMap<String, Object> parameters = new LinkedHashMap<String, Object>();
//        return client.invoke(type, "io.iec.edp.caf.databaseobject.rpcapi.service.DatabaseObjectRpcService.getDatabaseObjectList", su, parameters, null);
//    }

    /**
     * 根据ID获取数据库对象详细信息
     *
     * @return 数据库对象详细信息
     */
    @Override
    public final AbstractDatabaseObject getDatabaseObject(String dboId) {
        AbstractDatabaseObject result = null;
        if(FileUtils.isMappingOpen()){
            DatabaseObjectTable table = getDatabaseObjectFromMaping(dboId);
            if (table!=null ) {
                return table;
            }
        }
        try {
            AbstractDatabaseObject databaseObject = (AbstractDatabaseObject) DatabaseObjectCacheManager.getInstance().getDatabaseObjectContent(dboId);
            if (databaseObject != null) {
                if (databaseObject.getType() == DatabaseObjectType.Table) {
                    return ((DatabaseObjectTable) databaseObject).clone();
                } else if (databaseObject.getType() == DatabaseObjectType.View) {
                    return ((DatabaseObjectView) databaseObject).clone();
                } else if (databaseObject.getType() == DatabaseObjectType.TempTable) {
                    return ((DatabaseObjectTempTable) databaseObject).clone();
                }
            } else {
                result = getDatabaseObjectFromTable(dboId);
            }
        } catch (Exception e) {
            throw new RuntimeException("根据ID获取数据库对象报错，对象ID为" + dboId, e);
        }
        return result;
    }

    @Override
    public void clearDatabaseObjectMappingContent() {
        DatabaseObjectCacheManager.mappingCache.clear();
        DatabaseObjectCacheManager.idmappingCache.clear();
    }

    @Override
    public void clearDatabaseObjectMappingContentByIds(String ids) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            List<String> keys = Arrays.asList(mapper.readValue(ids, String[].class));
            for(String key:keys){
                DatabaseObjectCacheManager.mappingCache.remove(key);
                DatabaseObjectCacheManager.idmappingCache.remove(key);
            }
        } catch (Exception e) {
            throw new RuntimeException("清理一组DBO缓存出错：", e);
        }
    }

    @Override
    public AbstractDatabaseObject getDatabaseObject(String dboId, String su) {
        try {
            LinkedHashMap<String, Object> parameters = new LinkedHashMap<String, Object>();
            parameters.put("dboId", dboId);
            return client.invoke(AbstractDatabaseObject.class, "io.iec.edp.caf.databaseobject.rpcapi.service.DatabaseObjectRpcService.getDatabaseObject", su, parameters, null);
        } catch (Exception e) {
            throw new RuntimeException("根据ID获取数据库对象报错，对象ID为" + dboId, e);
        }
    }

    @Override
    public void clearDatabaseObjectContent() {
        DatabaseObjectCacheManager.getInstance().clearDatabaseObjectContent();
    }

    @Override
    public void clearDatabaseObjectContentByIds(String ids) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            List<String> keys = Arrays.asList(mapper.readValue(ids, String[].class));
            DatabaseObjectCacheManager.getInstance().clearDatabaseObjectContentByIds(keys);
        } catch (Exception e) {
            throw new RuntimeException("清理一组DBO缓存出错：", e);
        }
    }

    @Override
    public void clearDatabaseObjectContentById(String id) {
        DatabaseObjectCacheManager.getInstance().removeDatabaseObjectContent(id);
    }

    @Override
    public void addDatabaseObjectContent(AbstractDatabaseObject databaseObject) {
        DatabaseObjectCacheManager.getInstance().addDatabaseObjectContent(databaseObject.getId(), databaseObject);
    }

    private AbstractDatabaseObject getDatabaseObjectFromGspDbo(GspDatabaseObject gspDatabaseObject) {
        if (gspDatabaseObject != null) {
            if (gspDatabaseObject.getContent() == null || gspDatabaseObject.getContent().length() <= 0) {
                throw new RuntimeException("数据库对象内容不能为空");
            }

            DatabaseObjectCommonUtil util = new DatabaseObjectCommonUtil();
            try {
                AbstractDatabaseObject object = util.deserialze(DatabaseObjectType.forValue(gspDatabaseObject.getType()), gspDatabaseObject.getContent());
                object.setLastModifiedTime(gspDatabaseObject.getLastModifiedTime());
                return object;
            } catch (Exception e) {
                throw new RuntimeException("数据库对象" + gspDatabaseObject.getCode() + "反序列化失败:" + e.getMessage(), e);
            }
        }
        return null;
    }

    private AbstractDatabaseObject getDatabaseObjectInfoFromGspDbo(GspDatabaseObject gspDatabaseObject) throws Exception {
        if (gspDatabaseObject != null) {
            if (gspDatabaseObject.getContent() == null || gspDatabaseObject.getContent().length() <= 0) {
                throw new RuntimeException("数据库对象内容不能为空");
            }
            DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
            return commonUtil.deserialze(gspDatabaseObject.getContent());
        }
        return null;
    }

    /**
     * 根据编号获取DBO基础信息列表
     *
     * @param dboCode 数据库对象编号
     * @return 数据库对象基本信息列表
     */

    @Override
    public final AbstractDatabaseObject getDatabaseObjectByCode(String dboCode) {
        checkForEmptyString(dboCode, "dboCode");
        AbstractDatabaseObject result = null;
        try {
            GspDatabaseObject gspDatabaseObject = repository.findByCode(dboCode);

            if (gspDatabaseObject != null) {
                result = getDatabaseObjectFromGspDbo(gspDatabaseObject);
            }
        } catch (Exception e) {
            throw new RuntimeException("根据编号获取数据库对象报错，对象编号为" + dboCode, e);
        }
        return result;
    }

    @Override
    public AbstractDatabaseObject getDatabaseObjectByCode(String dboCode, String su) {
        try {
            LinkedHashMap<String, Object> parameters = new LinkedHashMap<String, Object>();
            parameters.put("dboCode", dboCode);
            return client.invoke(AbstractDatabaseObject.class, "io.iec.edp.caf.databaseobject.rpcapi.service.DatabaseObjectRpcService.getDatabaseObjectByCode", su, parameters, null);
        } catch (Exception e) {
            throw new RuntimeException("根据编号获取数据库对象报错，对象编号为" + dboCode, e);
        }
    }

    @Override
    public final String getDatabaseObjectCodeById(String dboId) {
        checkForEmptyString(dboId, "dboId");
        try {
            AbstractDatabaseObject databaseObject = getDatabaseObject(dboId);
            if (databaseObject != null) {
                return databaseObject.getCode();
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new RuntimeException("获取数据库对象编号报错，数据库对象ID为：" + dboId, e);
        }
    }

    @Override
    public final List<DimensionEntity> getDimensionListByDboId(String dboId) {
        checkForEmptyString(dboId, "dboId");
        try {
            AbstractDatabaseObject databaseObject = getDatabaseObject(dboId);
            if (databaseObject != null && databaseObject.getType() == DatabaseObjectType.Table) {
                DatabaseObjectTable table = (DatabaseObjectTable) ((databaseObject instanceof DatabaseObjectTable) ? databaseObject : null);
                assert table != null;
                if (table.getHasNameRule()) {
                    List<DimensionEntity> result = new ArrayList<>();

                    for (DimensionStrategyWithOrder strategy : table.getDboTableNameRule().getDimensionStrategyWithOrder()) {
                        result.add(strategy.getDimensionEntity());
                    }
                    return result;
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new RuntimeException("获取数据库对象编号报错，数据库对象ID为：" + dboId, e);
        }
    }

    @Override
    public Map<String, Boolean> isTablesExist(List<String> tableNames) {
        Map<String, Boolean> result = new HashMap<>();
        String realtableName = "";
        try {
            DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
            DBInfo dbInfo = service.getDbInfo();
            DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
            List<String> dbTableNames = commonUtil.getDbTables(dbInfo,tableNames);
            for (String tableName : tableNames) {
                result.put(tableName, false);
                for (String obj : dbTableNames) {
                    if (obj.equalsIgnoreCase(tableName)) {
                        result.put(tableName, true);
                        break;
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("判断表[" + realtableName + "]是否存在出错：" + e);
        }
        return result;
    }

    @Override
    public TempTableContext creatTempTables(String dboId) {

        AbstractDatabaseObject object = getDatabaseObject(dboId);
        //临时表表名为真正表名加bizContext后10位
        String bizContext = CAFContext.current.getBizContext().getId();
        DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
        DBInfo dbInfo = service.getDbInfo();
        String tempTableCode = object.getCode() + bizContext.substring(bizContext.length() - 10);
        object.setCode(tempTableCode);
        List<AbstractDatabaseObject> objects = new ArrayList<>();
        objects.add(object);
        DboDeployManager dboDeployManager = new DboDeployManager();
        Map<String, List<String>> sqlMap = dboDeployManager.getTempTablesCreateSql(objects, dbInfo);
        try {
            DatabaseManager databaseManager = DatabaseManager.getInstance();
            Database database = databaseManager.getDatabase();
            for (String sql : sqlMap.get(tempTableCode.toLowerCase())) {
                log.debug("执行的临时表创建SQL为：" + sql);
                database.execute(sql);
            }
            TempTableContext context = new TempTableContext();
            //设置成真正表名
            if (dbInfo.getDbType() == DbType.SQLServer) {
                tempTableCode = "#" + tempTableCode;
            }
            context.setTableName(tempTableCode);
            return context;
        } catch (Exception e) {
            throw new RuntimeException("根据dboId创建临时表出错：" + e);
        }
    }

    @Override
    public void dropTempTable(TempTableContext context, String dboId) {
        DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
        DBInfo dbInfo = service.getDbInfo();
        //只有Oracle、DM、Oscar使用全局临时表，需要主动删除
        if (dbInfo.getDbType() == DbType.Oracle || dbInfo.getDbType() == DbType.DM || dbInfo.getDbType() == DbType.Oscar) {
            //移除缓存
            DatabaseObjectCacheManager.getInstance().removeDatabaseObjectContent(dboId);

            String table = context.getTableName();
            List<String> tables = new ArrayList<>();
            tables.add(table);
            Map<String, Boolean> result = isTablesExist(tables);
            if (result.get(table)) {
                String truncateSql = "TRUNCATE TABLE " + table;
                String dropSql = "DROP TABLE " + table;
                DatabaseManager databaseManager = DatabaseManager.getInstance();

                try {
                    Database database = databaseManager.getDatabase();
                    database.execute(truncateSql);
                    database.execute(dropSql);
                } catch (Exception e) {
                    throw new RuntimeException("删除临时表[" + table + "]出错：" + e);
                }
            }
        }
    }


    /**
     * 保存数据库对象
     *
     * @param databaseObject 数据库对象实体
     */
    @Override
    public final void saveDatabaseObject(AbstractDatabaseObject databaseObject) {
        try {
            DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
            checkUtil.checkDatabaseObjectAvailable(databaseObject);
            AbstractDatabaseObject result = getDatabaseObjectByCode(databaseObject.getCode());
            if (!isExistDatabaseObject(databaseObject.getId())) {
                if (result != null) {
                    throw new RuntimeException("数据库存储数据库对象的表中已存在编号为" + databaseObject.getCode() + "的数据库对象，如果原有数据库对象已废弃，请删除后重试。否则，修改dbo文件里的Code后重试");
                }

                createDatabaseObject(databaseObject);
            } else {
                if (result != null) {
                    if (result.getId().equals(databaseObject.getId())) {
                        updateDatabaseObject(databaseObject);
                    } else {
                        throw new RuntimeException("数据库存储数据库对象的表中除了当前数据库对象外，还有重编号的数据库对象，请确认。数据库对象编号为：" + databaseObject.getCode());
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("向数据库表中保存数据库对象报错，数据库对象编号为：" + databaseObject.getCode(), e);
        }
    }

    private void createDatabaseObject(AbstractDatabaseObject databaseObject) {
        checkForNullReference(databaseObject, "databaseObject");
        checkForEmptyString(databaseObject.getCode(), "Code");
        if (databaseObject.getType() == DatabaseObjectType.Table || databaseObject.getType() == DatabaseObjectType.TempTable) {
            checkForNullReference(((DatabaseObjectTable) databaseObject).getColumns(), "columns");
        }
        try {
            GspDatabaseObject gspDatabaseObject = buildGspDatabaseObject(databaseObject);
            gspDatabaseObject.setCreatedTime(LocalDateTime.now());
            gspDatabaseObject.setLastModifiedTime(LocalDateTime.now());
            //gspDatabaseObject.Content = JToken.Parse(gspDatabaseObject.Content).toString();
            repository.save(gspDatabaseObject);
        } catch (Exception e) {
            throw new RuntimeException(String.format("向数据库表中新增数据库对象报错，数据库对象编号为：%1$s", databaseObject.getCode()), e);
        }
    }

    private void updateDatabaseObject(AbstractDatabaseObject databaseObject) {
        checkForNullReference(databaseObject, "databaseObject");
        checkForEmptyString(databaseObject.getCode(), "Code");
        if (databaseObject.getType() == DatabaseObjectType.Table || databaseObject.getType() == DatabaseObjectType.TempTable) {
            checkForNullReference(((DatabaseObjectTable) databaseObject).getColumns(), "columns");
        }
        try {
            GspDatabaseObject gspDatabaseObject = buildGspDatabaseObject(databaseObject);
            gspDatabaseObject.setCreatedTime(getCreatedTime(databaseObject.getId()));
//			gspDatabaseObject.setContent(JToken.Parse(gspDatabaseObject.Content).toString());
            gspDatabaseObject.setLastModifiedTime(LocalDateTime.now());
            repository.save(gspDatabaseObject);
            DatabaseObjectCacheManager.getInstance().removeDatabaseObjectContent(databaseObject.getId());
        } catch (Exception e) {
            throw new RuntimeException("更新数据库表中数据库对象报错，数据库对象编号为：" + databaseObject.getCode(), e);
        }
    }

    private LocalDateTime getCreatedTime(String id) {
        return repository.findById(id).get().getCreatedTime();
    }

    /**
     * 数据库对象是否存在
     *
     * @param dboId 数据库对象ID
     * @return 如果存在，返回true；如果不存在，返回false
     */
    @Override
    public final boolean isExistDatabaseObject(String dboId) {
        checkForEmptyString(dboId, "dboId");
        try {
            return repository.existsById(dboId);
        } catch (Exception e) {
            throw new RuntimeException("根据ID判断数据库表中数据库对象是否存在报错，数据库对象ID为：" + dboId, e);
        }
    }

    @Override
    public final List<AbstractDatabaseObject> getDatabaseObjectByRule(String ruleCode) {
        try {
            List<AbstractDatabaseObject> result = new ArrayList<>();
            List<GspDatabaseObject> gspDatabaseObjects = repository.findAllByRuleCode(ruleCode);
            if (gspDatabaseObjects.size() <= 0) {
                return null;
            }
            for (GspDatabaseObject gspDatabaseObject : gspDatabaseObjects) {
                result.add(getDatabaseObject(gspDatabaseObject.getId()));
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("根据规则编号获取数据库对象列表报错，规则编号为" + ruleCode, e);
        }
    }

    @Override
    public List<String> getTableColumnNamesByCode(String dboCode) {

        List<String> result = new ArrayList<>();
        checkForEmptyString(dboCode, "dboCode");
        try {
            AbstractDatabaseObject databaseObject = getDatabaseObjectByCode(dboCode);
            if (databaseObject == null) {
                throw new RuntimeException("编号为" + dboCode + "的数据库对象不存在，请确认");
            }

            if (databaseObject.getType() == DatabaseObjectType.Table) {
                DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
                result = getColumnNames(table.getColumns(), table.getMultiLanguageColumns());
            } else if (databaseObject.getType() == DatabaseObjectType.View) {
                DatabaseObjectView view = (DatabaseObjectView) databaseObject;
                result = getColumnNames(view.getColumns(), view.getMultiLanguageColumns());
            } else if (databaseObject.getType() == DatabaseObjectType.TempTable) {
                DatabaseObjectTempTable tempTable = (DatabaseObjectTempTable) databaseObject;
                result = getColumnNames(tempTable.getColumns(), tempTable.getMultiLanguageColumns());
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("根据DBO编号获取字段名列表出错，当前DBO编号为" + dboCode, e);
        }
    }

    private List<String> getColumnNames(List<DatabaseObjectColumn> columns, List<String> multiLanguageColumns) {
        List<String> result = new ArrayList<>();
        List<String> languages = getLanguages();
        for (DatabaseObjectColumn column : columns) {
            String columnCode = column.getCode();
            if (multiLanguageColumns != null && multiLanguageColumns.size() > 0 && multiLanguageColumns.contains(column.getId())) {
                for (String language : languages) {
                    String columnCodeWithI18n = columnCode + language;
                    result.add(columnCodeWithI18n);
                }
            } else {
                result.add(columnCode);
            }
        }
        return result;
    }

    @Override
    public Map<String, List<String>> getTableColumnNamesByCode(List<String> dboCodes) {
        Map<String, List<String>> result = new HashMap<>();
        for (String dboCode : dboCodes) {
            result.put(dboCode, getTableColumnNamesByCode(dboCode));
        }
        return result;
    }

    public final String getTableNameWithDimensionValue(String dboid) {
        return getTableNameWithDimensionValue(dboid, null);
    }

    @Override
    public final String getTableNameWithDimensionValue(String dboId, Map<String, String> dimensionInfo) throws RuntimeException {

        //如果flag为true的话，需要走原先的逻辑，不走映射逻辑
        boolean flag = false;

        checkForEmptyString(dboId, "dboId");

        AbstractDatabaseObject databaseObject = null;

        if(FileUtils.isMappingOpen()){

            if(DatabaseObjectCacheManager.idmappingCache.get(dboId)!=null){

                String mappingId = DatabaseObjectCacheManager.idmappingCache.get(dboId);

                databaseObject = (AbstractDatabaseObject) DatabaseObjectCacheManager.getInstance().getDatabaseObjectContent(mappingId);

                if (databaseObject == null) {
                    databaseObject = getDatabaseObjectFromTable(mappingId);
                }
            }else if(DatabaseObjectCacheManager.mappingCache.size()==0){
                getMappingTable(null);
                String mappingId = DatabaseObjectCacheManager.idmappingCache.get(dboId);
                if(mappingId != null){
                    databaseObject = (AbstractDatabaseObject) DatabaseObjectCacheManager.getInstance().getDatabaseObjectContent(mappingId);

                    if (databaseObject == null) {
                        databaseObject = getDatabaseObjectFromTable(DatabaseObjectCacheManager.idmappingCache.get(dboId));
                    }
                }else{
                    flag = true;
                }
            }else{
                flag = true;
            }
        }else{
            flag = true;
        }
        if(flag){
            databaseObject = (AbstractDatabaseObject) DatabaseObjectCacheManager.getInstance().getDatabaseObjectContent(dboId);

            if (databaseObject == null) {
                databaseObject = getDatabaseObjectFromTable(dboId);
            }
        }
        if (databaseObject == null) {
            throw new RuntimeException("数据库对象表中不存在为" + dboId + "的数据库对象，请确认。");
        }
        return getTableName(databaseObject, dimensionInfo);
    }

    @Override
    public List<String> getTableNamesWithDimensionValues(String dboId, Map<String, List<String>> dimensionInfo) {
        checkForEmptyString(dboId, "dboId");
        AbstractDatabaseObject databaseObject = null;
        databaseObject = DatabaseObjectCacheManager.getInstance().getDatabaseObjectContent(dboId);
        if (databaseObject == null) {
            databaseObject = getDatabaseObjectFromTable(dboId);
        }
        if (databaseObject == null) {
            throw new RuntimeException("数据库对象表中不存在为" + dboId + "的数据库对象，请确认。");
        }
        return getTableNames(databaseObject, dimensionInfo);
    }

    private AbstractDatabaseObject getDatabaseObjectFromTable(String dboId) {
        AbstractDatabaseObject result = null;
        Optional<GspDatabaseObject> gspDatabaseObjectOpt = repository.findById(dboId);
        if (gspDatabaseObjectOpt.isPresent()) {
            result = getDatabaseObjectFromGspDbo(gspDatabaseObjectOpt.get());
        }
        if (result != null) {
            if (result.getType() == DatabaseObjectType.Table) {
                DatabaseObjectCacheManager.getInstance().addDatabaseObjectContent(dboId, ((DatabaseObjectTable) result).clone());
            } else if (result.getType() == DatabaseObjectType.View) {
                DatabaseObjectCacheManager.getInstance().addDatabaseObjectContent(dboId, ((DatabaseObjectView) result).clone());
            } else if (result.getType() == DatabaseObjectType.TempTable) {
                DatabaseObjectCacheManager.getInstance().addDatabaseObjectContent(dboId, ((DatabaseObjectTempTable) result).clone());
            }
        }
        return result;
    }

    private String getTableNameByCode(String dboCode, Map<String, String> dimensionInfo) {
        checkForEmptyString(dboCode, "dboCode");

        AbstractDatabaseObject databaseObject = getDatabaseObjectByCode(dboCode);
        if (databaseObject == null) {
            throw new RuntimeException("数据库对象表中不存在ID为" + dboCode + "的数据库对象，请确认。");
        }

        return getTableName(databaseObject, dimensionInfo);
    }

    private String getTableName(AbstractDatabaseObject databaseObject, Map<String, String> dimensionInfo) {
        String tableName = "";
        if (databaseObject.getType() == DatabaseObjectType.View) {
            DatabaseObjectView view = (DatabaseObjectView) databaseObject;
            if (view.getHasNameRule()) {
                tableName = getTableNameByCodeAndRule(databaseObject.getCode(), view.getDboTableNameRule(), dimensionInfo);
            } else {
                tableName = databaseObject.getCode();
            }
        } else if (databaseObject.getType() == DatabaseObjectType.Table) {
            DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
            if (table.getHasNameRule()) {
                tableName = getTableNameByCodeAndRule(databaseObject.getCode(), table.getDboTableNameRule(), dimensionInfo);
            } else {
                tableName = databaseObject.getCode();
            }
        } else if (databaseObject.getType() == DatabaseObjectType.TempTable) {
            DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
            DBInfo dbInfo = service.getDbInfo();
            //临时表表名为真正表名加bizContext后10位,SqlServer要加#
            String bizContext = CAFContext.current.getBizContext().getId();
            tableName = databaseObject.getCode() + bizContext.substring(bizContext.length() - 10);
            if (dbInfo.getDbType() == DbType.SQLServer) {
                tableName = "#" + tableName;
            }
        }
        return tableName;
    }

    private List<String> getTableNames(AbstractDatabaseObject databaseObject, Map<String, List<String>> dimensionInfo) {
        List<String> tableNames = new ArrayList<>();
        String tableName = "";
        if (databaseObject.getType() == DatabaseObjectType.View) {
            DatabaseObjectView view = (DatabaseObjectView) databaseObject;
            if (view.getHasNameRule()) {
                tableNames = getTableNamesByCodeAndRule(databaseObject.getCode(), view.getDboTableNameRule(), dimensionInfo);
            } else {
                tableName = databaseObject.getCode();
                tableNames.add(tableName);
            }
        } else if (databaseObject.getType() == DatabaseObjectType.Table) {
            DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
            if (table.getHasNameRule()) {
                tableNames = getTableNamesByCodeAndRule(databaseObject.getCode(), table.getDboTableNameRule(), dimensionInfo);
            } else {
                tableName = databaseObject.getCode();
                tableNames.add(tableName);
            }
        } else if (databaseObject.getType() == DatabaseObjectType.TempTable) {
            DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
            DBInfo dbInfo = service.getDbInfo();
            String bizContext = CAFContext.current.getBizContext().getId();
            tableName = databaseObject.getCode() + bizContext.substring(bizContext.length() - 10);
            if (dbInfo.getDbType() == DbType.SQLServer) {
                tableName = "#" + tableName;
            }
            tableNames.add(tableName);
        }
        return tableNames;
    }

    private String getTableNameByCodeAndRule(String code, DBOTableNameRule dboTableNameRule, Map<String, String> dimensionInfo) {
        String tableName;
        ITableNameRuleManager rtmanager;
        try {
            rtmanager = TableNameHelper.getInstance().GetManager(dboTableNameRule.getId());
        } catch (Exception e) {
            throw new RuntimeException("获取表名规则扩展实现配置报错，表名规则为：" + dboTableNameRule.getId(), e);
        }
        if (rtmanager == null) {
            throw new RuntimeException("未获取到表名规则扩展实现，表名规则为：" + dboTableNameRule.getId());
        }
        tableName = rtmanager.getTableName(code, dboTableNameRule, dimensionInfo);
        DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
        checkUtil.checkObjectCode(tableName);
        return tableName;
    }

    private List<String> getTableNamesByCodeAndRule(String code, DBOTableNameRule dboTableNameRule, Map<String, List<String>> dimensionInfo) {
        List<String> tableNames;
        ITableNameRuleManager rtmanager;
        try {
            rtmanager = TableNameHelper.getInstance().GetManager(dboTableNameRule.getId());
        } catch (Exception e) {
            throw new RuntimeException("获取表名规则扩展实现配置报错，表名规则为：" + dboTableNameRule.getId(), e);
        }
        if (rtmanager == null) {
            throw new RuntimeException("未获取到表名规则扩展实现，表名规则为：" + dboTableNameRule.getId());
        }
        tableNames = rtmanager.getTableNames(code, dboTableNameRule, dimensionInfo);
        DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
        for (String tableName : tableNames) {
            checkUtil.checkObjectCode(tableName);
        }
        return tableNames;
    }

    @Override
    public List<String> getTableNamesWithDimensionValue(List<String> dboCodes, Map<String, String> dimensionInfo) {
        List<String> tableNames = new ArrayList<>();
        for (String dboCode : dboCodes) {
            tableNames.add(getTableNameByCode(dboCode, dimensionInfo));
        }
        return tableNames;
    }

    /**
     * 获取多语数据库对象表列表
     *
     * @return 数据库对象表列表
     */
    @Override
    public final List<DatabaseObjectTable> getI18nObjectTables() {
        List<DatabaseObjectTable> result = new ArrayList<>();
        try {
            List<GspDatabaseObject> list = repository.findAllByIsI18NObject("1");
            if (list != null && list.size() > 0) {
                for (GspDatabaseObject databaseObject : list) {
                    DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
                    result.add((DatabaseObjectTable) commonUtil.deserialze(databaseObject.getContent()));
                }
            }

        } catch (Exception e) {
            throw new RuntimeException("获取启用多语的数据库对象列表报错", e);
        }
        return result;
    }

    @Override
    public final void deleteDatabaseObject(String dboID) {
        try {
            checkForEmptyString(dboID, "dboID");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            repository.deleteById(dboID);
        } catch (Exception e) {
            throw new RuntimeException("根据ID删除数据库对象报错，数据库对象ID为" + dboID, e);
        }
    }

    private GspDatabaseObject buildGspDatabaseObject(AbstractDatabaseObject databaseObject) throws IOException {
        GspDatabaseObject result = new GspDatabaseObject();
        result.setId(databaseObject.getId());
        result.setCode(databaseObject.getCode());
        result.setName(databaseObject.getName());
        if (databaseObject.getType() == DatabaseObjectType.Table) {
            DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
            result.setBusinessObjectId(table.getBusinessObjectId());
            result.setIsI18NObject(table.isI18NObject() ? "1" : "0");
            if (table.getTenantIdentityColumn() != null) {
                result.setTenantIDColumnCode(table.getTenantIdentityColumn().getCode());
            }
            result.setIsFiscalTable("0");
        } else {
            DatabaseObjectView view = (DatabaseObjectView) databaseObject;
            result.setBusinessObjectId(view.getBusinessObjectId());
            result.setIsI18NObject(view.isI18nObject() ? "1" : "0");
            result.setIsFiscalTable("0");
            //result.RuleID = null;
        }
        result.setType(databaseObject.getType().getValue());
        result.setVersion(databaseObject.getVersion());
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        result.setContent(commonUtil.serialze(databaseObject));
        return result;
    }

    /**
     * 根据传入的表ID和字段ID返回字段编号。
     * 如果字段是多语的，则返回带多语后缀的字段编号；
     * 如果字段不是多语的，则只返回字段编号。
     *
     * @param tableId   表ID
     * @param columnIds 字段ID列表
     * @return 带多语后缀的字段编号列表
     */
    @Override
    public final List<String> getColumnCodeWithI18n(String tableId, List<String> columnIds) {
        List<String> columnCodesWithI18n = new ArrayList<>();
        checkForEmptyString(tableId, "tableId");
        checkForNullReference(columnIds, "columnIds");
        try {

            AbstractDatabaseObject databaseObject = getDatabaseObject(tableId);

            if (databaseObject == null) {
                throw new RuntimeException("ID为" + tableId + "的数据库对象不存在，请确认");
            }
            if (databaseObject.getType() == DatabaseObjectType.Table) {
                DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
                columnCodesWithI18n = getColumnsNameById(table.getColumns(), table.getMultiLanguageColumns(), columnIds);
            } else if (databaseObject.getType() == DatabaseObjectType.View) {
                DatabaseObjectView view = (DatabaseObjectView) databaseObject;
                columnCodesWithI18n = getColumnsNameById(view.getColumns(), view.getMultiLanguageColumns(), columnIds);
            } else if (databaseObject.getType() == DatabaseObjectType.TempTable) {
                DatabaseObjectTempTable tempTable = (DatabaseObjectTempTable) databaseObject;
                columnCodesWithI18n = getColumnsNameById(tempTable.getColumns(), tempTable.getMultiLanguageColumns(), columnIds);
            }
            return columnCodesWithI18n;
        } catch (Exception e) {
            throw new RuntimeException("根据表ID和字段ID列表获取带多语后缀的字段编号出错，当前表ID为" + tableId, e);
        }
    }

    private List<String> getColumnsNameById(List<DatabaseObjectColumn> columns, List<String> multiLanguageColumns, List<String> columnIds) {
        List<String> columnCodesWithI18n = new ArrayList<>();
        LanguageService languageService = SpringBeanUtils.getBean(LanguageService.class);
        String language = languageService.getFieldSuffix();
        for (String columnId : columnIds) {
            if (columnId == null || columnId.length() <= 0) {
                throw new RuntimeException("当前传入的column为空，columnID为" + columnId);
            }
            DatabaseObjectColumn column = columns.stream().filter((item) -> item.getId().equals(columnId)).findFirst().orElse(null);

            if (column == null) {
                throw new RuntimeException("当前column不是数据库对象表里的字段，columnID为" + columnId);
            }
            String columnCode = column.getCode();
            if (multiLanguageColumns != null && multiLanguageColumns.size() > 0 && multiLanguageColumns.contains(columnId)) {
                String columnCodeWithI18n = columnCode + language;
                columnCodesWithI18n.add(columnCodeWithI18n);
            } else {
                columnCodesWithI18n.add(columnCode);
            }
        }
        return columnCodesWithI18n;
    }


    /**
     * 根据传入的表ID和字段ID返回字段编号。
     * 多语则返回所有种类语言的字段编号。
     *
     * @param tableId
     * @param columnIds
     * @return
     */
    @Override
    public Map<String, List<String>> getAllColumnCodeWithI18n(String tableId, List<String> columnIds) {

        Map<String, List<String>> columnCodesWithI18n = new HashMap<>();
        checkForEmptyString(tableId, "tableId");
        checkForNullReference(columnIds, "columnIds");
        try {

            AbstractDatabaseObject databaseObject = getDatabaseObject(tableId);

            if (databaseObject == null) {
                throw new RuntimeException("ID为" + tableId + "的数据库对象不存在，请确认");
            }

            if (databaseObject.getType() == DatabaseObjectType.Table) {
                DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
                columnCodesWithI18n = getAllLanguageColumnsNameById(table.getColumns(), table.getMultiLanguageColumns(), columnIds);
            } else if (databaseObject.getType() == DatabaseObjectType.View) {
                DatabaseObjectView view = (DatabaseObjectView) databaseObject;
                columnCodesWithI18n = getAllLanguageColumnsNameById(view.getColumns(), view.getMultiLanguageColumns(), columnIds);
            } else if (databaseObject.getType() == DatabaseObjectType.TempTable) {
                DatabaseObjectTempTable tempTable = (DatabaseObjectTempTable) databaseObject;
                columnCodesWithI18n = getAllLanguageColumnsNameById(tempTable.getColumns(), tempTable.getMultiLanguageColumns(), columnIds);
            }
            return columnCodesWithI18n;
        } catch (Exception e) {
            throw new RuntimeException("根据表ID和字段ID列表获取带多语后缀的字段编号出错，当前表ID为" + tableId, e);
        }
    }

    private Map<String, List<String>> getAllLanguageColumnsNameById(List<DatabaseObjectColumn> columns, List<String> multiLanguageColumns, List<String> columnIds) {
        Map<String, List<String>> ret = new HashMap<>();

        //获取所有语言类型：
        List<String> allLanguages = getLanguages();

        for (String columnId : columnIds) {
            if (columnId == null || columnId.length() <= 0) {
                throw new RuntimeException("当前传入的column为空，columnID为" + columnId);
            }
            DatabaseObjectColumn column = columns.stream().filter((item) -> item.getId().equals(columnId)).findFirst().orElse(null);

            if (column == null) {
                throw new RuntimeException("当前column不是数据库对象表里的字段，columnID为" + columnId);
            }
            String columnCode = column.getCode();
            if (multiLanguageColumns != null && multiLanguageColumns.size() > 0 && multiLanguageColumns.contains(columnId)) {
                List<String> tempList = new ArrayList<>();
                for (String language : allLanguages) {
                    String columnCodeWithI18n = columnCode + language;
                    tempList.add(columnCodeWithI18n);
                }
                ret.put(columnCode, tempList);
            } else {
                List<String> tempList = new ArrayList<>();
                tempList.add(columnCode);
                ret.put(columnCode, tempList);
            }
        }
        return ret;
    }


    /**
     * 根据业务对象字段关联属性获取数据库对象列表
     *
     * @param businessObjectID
     * @return 数据库对象列表
     */
    @Override
    public final List<AbstractDatabaseObject> getDatabaseObjectByBOID(String businessObjectID) {
        checkForEmptyString(businessObjectID, "businessObjectID");
        try {

            List<AbstractDatabaseObject> result = new ArrayList<>();
            List<GspDatabaseObject> list = repository.findAllByBusinessObjectId(businessObjectID);
            if (list != null && list.size() > 0) {
                for (GspDatabaseObject item : list) {
                    result.add(getDatabaseObjectInfoFromGspDbo(item));
                }
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("根据业务对象ID获取数据库对象列表报错，业务对象ID为" + businessObjectID, e);
        }
    }

    private void checkForEmptyString(String strValue, String strName) throws RuntimeException {
        if (strValue == null || strValue.length() <= 0) {
            throw new RuntimeException(strName + "不能为空");
        }
    }

    private void checkForNullReference(Object objectValue, String objectName) throws RuntimeException {
        if (objectValue == null) {
            throw new RuntimeException(objectName + "不能为null");
        }
    }

    private ArrayList<String> getLanguages() {
        ArrayList<String> result = new ArrayList<>();
        result.add("_CHS");
        result.add("_EN");
        result.add("_CHT");
        result.add("_ES");
        result.add("_PT");
        return result;
    }

    public DatabaseObjectTable getDatabaseObjectFromMaping(String dboId) {
        DatabaseObjectTable table = null;
        try {
            Map mappingMap = DatabaseObjectCacheManager.mappingCache;
            //TODO 统一入口操作缓存
            if(mappingMap.size()==0){
                Map<String,DatabaseObjectTable> map = getMappingTable(null);
                if(mappingMap.get(dboId)!=null){
                    table = (DatabaseObjectTable) mappingMap.get(dboId);
                }
            }else if(mappingMap.get(dboId)!=null){
                table = (DatabaseObjectTable) mappingMap.get(dboId);
            }else{
//                List<String> dboids =new ArrayList<>();
//                dboids.add(dboId);
//                Map map = getMappingTable(dboids);
//                table = (DatabaseObjectTable) map.get(dboId);
            }
        } catch (Exception ex) {
            throw new RuntimeException("根据code或dboId获取映射对象出错{}", ex);
        }
        return table;
    }

    public Map<String,DatabaseObjectTable> getMappingTable(List<String> dboIds){
        Map<String,DatabaseObjectTable> tableMap =new ConcurrentHashMap<>();
        List<GspDatabaseObjectMapping> mappingList = new ArrayList<>();
        if(dboIds==null || dboIds.size()==0){
            mappingList = this.mappingRepository.findAll();
        }else {
            mappingList = this.mappingRepository.findAllByDboIdIn(dboIds);
        }
        if(mappingList.size()>0){
            for(GspDatabaseObjectMapping mapping:mappingList){
                if (mapping != null) {
                    String dboIdMapping = mapping.getDboIdMapping() == null ? null : mapping.getDboIdMapping();
                    if (dboIdMapping != null) {
                        DatabaseObjectCacheManager.idmappingCache.put(mapping.getDboId(),mapping.getDboIdMapping());
                        String key = mapping.getDboId();
                        DatabaseObjectTable tableCache = (DatabaseObjectTable) DatabaseObjectCacheManager.getInstance().getDatabaseObjectContent(mapping.getDboId());
                        DatabaseObjectTable table = null;
                        if(tableCache!=null){
                            table=tableCache.clone();
                        }
                        if (table == null) {
                            table = (DatabaseObjectTable) getDatabaseObjectFromTable(mapping.getDboId());
                        }
                        DatabaseObjectTable tableMappingCache = (DatabaseObjectTable) DatabaseObjectCacheManager.getInstance().getDatabaseObjectContent(dboIdMapping);
                        DatabaseObjectTable tableMapping =  null;
                        if(tableMappingCache!=null){
                            tableMapping=tableMappingCache.clone();
                        }
                        if (tableMapping == null) {
                            tableMapping = (DatabaseObjectTable) getDatabaseObjectFromTable(dboIdMapping);
                        }
                        List<GspDatabaseObjectColumnMapping> columnMappings = (List<GspDatabaseObjectColumnMapping>) this.columnMappingRepository.findAllByDboId(mapping.getDboId());
                        if (columnMappings != null && columnMappings.size() > 0) {
                            List<DatabaseObjectColumn> columns = table.getColumns();
                            List<DatabaseObjectColumn> mappingColumns = new ArrayList<>();
                            Map<String,GspDatabaseObjectColumnMapping> map = new HashMap<>();
                            for(GspDatabaseObjectColumnMapping columnMapping:columnMappings){
                                map.put(columnMapping.getColumnId(),columnMapping);
                            }
                            for (DatabaseObjectColumn column : columns) {
                                GspDatabaseObjectColumnMapping value = map.get(column.getId());
                                if (value!=null) {
                                    DatabaseObjectColumn mappingColumn = tableMapping.getColumnById(value.getColumnIdMapping());
                                    mappingColumn.setId(column.getId());
                                    mappingColumns.add(mappingColumn);
                                }else{
                                    DatabaseObjectColumn column1 = table.getColumnById(column.getId());
                                    mappingColumns.add(column1);
                                }
                            }
                            table.setColumns(mappingColumns);
                            table.setCode(tableMapping.getCode());
                            table.setName(tableMapping.getName());
                            tableMap.put(key,table);
                            DatabaseObjectCacheManager.mappingCache.put(key,table);
                        }else{
                            table.setName(tableMapping.getName());
                            table.setCode(tableMapping.getCode());
                            tableMap.put(key,table);
                            DatabaseObjectCacheManager.mappingCache.put(key,table);
                        }
                    }
                }
            }
        }
        return tableMap;
    }
}
